home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 11 / PC World Interactive 11.iso / share / multimed / effect / Common Files / QTVRUtilities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-12  |  43.8 KB  |  1,430 lines

  1. //////////
  2. //
  3. //    File:        QTVRUtilities.c
  4. //
  5. //    Contains:    Some utilities for working with QuickTime and QuickTime VR movies.
  6. //                All utilities start with the prefix "QTVRUtils_".
  7. //
  8. //    Written by:    Tim Monroe
  9. //
  10. //    Copyright:    ⌐ 1996-1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <21>         02/12/98    rtm        added QTVRUtils_HideHotSpotNames and her sisters, *Show* and *Toggle*
  15. //       <20>         01/27/98    rtm        revised QTVRUtils_IsQTVRMgrInstalled and QTVRUtils_GetQTVRVersion
  16. //       <19>         01/26/98    rtm        revised QTVRUtils_GetHotSpotName to look also in hot spot atom for name atom
  17. //       <18>         01/14/98    rtm        added QTVRUtils_SetControllerType and QTVRUtils_AddStr255ToAtomContainer
  18. //       <17>         10/20/97    rtm        added QTVRUtils_IsMultiNode; added Endian*_BtoN macros to file format routines
  19. //       <16>         10/17/97    rtm        fixed QTVRUtils_IsControllerButtonVisible behavior for speaker button
  20. //       <15>         10/07/97    rtm        added cannotFindAtomErr result code to QTVRUtils_Get*AtomData functions
  21. //       <14>         09/15/97    rtm        added QTVRUtils_ToggleControllerBar
  22. //       <13>         08/21/97    rtm        added QTVRUtils_IsControllerButtonVisible
  23. //       <12>         08/19/97    rtm        added #ifdefs to support Windows compilation
  24. //       <11>         08/05/97    rtm        added QTVRUtils_GetNodeComment; still needs testing
  25. //       <10>         07/27/97    rtm        fixed QTVRUtils_GetHotSpotCount; added QTVRUtils_GetHotSpotIDByIndex
  26. //       <9>         07/25/97    rtm        revised QTVRUtils_Get*AtomData functions to use QTCopyAtomDataToPtr;
  27. //                                    rewrote QTVRUtils_GetStringFromAtom
  28. //       <8>         07/24/97    rtm        removed sound volume utilities; added QTVRUtils_IsZoomAvailable;
  29. //                                    revised QTVRUtils_IsQTVRMovie to use GetUserDataItem, not GetUserData
  30. //       <7>         07/23/97    rtm        revised file format utilities; added QTVRUtils_Get*AtomData functions
  31. //       <6>         07/22/97    rtm        fixed QTVRUtils_GetHotSpotCount to make sure handle is actually resized
  32. //       <5>         07/21/97    rtm        added QTVRUtils_GetNodeCount
  33. //       <4>         06/04/97    rtm        fixed QTVRUtils_ShowControllerButton and QTVRUtils_HideControllerButton,
  34. //                                    and added some explanation of them; added QTVRUtils_ResetControllerButton
  35. //       <3>         02/03/97    rtm        revised QTVRUtils_ShowControllerButton and QTVRUtils_HideControllerButton 
  36. //                                    to use explicit flag
  37. //       <2>         12/03/96    rtm        added controller bar utilities
  38. //       <1>         11/27/96    rtm        first file
  39. //       
  40. //////////
  41.  
  42. // header files
  43.  
  44. #ifndef __QTVRUtilities__
  45. #include "QTVRUtilities.h"
  46. #endif
  47.  
  48. #include <math.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51.  
  52. #include "QTUtilities.h"
  53.  
  54.  
  55. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  56. //
  57. // General utilities.
  58. //
  59. // Use these functions to get information about the availability/features of QuickTime VR or other services.
  60. //
  61. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  62.  
  63. //////////
  64. //
  65. // QTVRUtils_TrapAvailable
  66. // Check to see whether a given trap is implemented. This is based on IM: Operating System Utilities (p. 8-22).
  67. //
  68. //////////
  69.  
  70. #if TARGET_OS_MAC
  71. Boolean QTVRUtils_TrapAvailable (short theTrapWord)
  72. {
  73.     TrapType        myTrapType;
  74.     short            myNumToolboxTraps;
  75.     
  76.     // determine whether this is a Toolbox or an Operating System trap
  77.     if ((theTrapWord & 0x0800) > 0)
  78.         myTrapType = ToolTrap;
  79.     else
  80.         myTrapType = OSTrap;
  81.  
  82.     if (myTrapType == ToolTrap) {
  83.         theTrapWord = theTrapWord & 0x07FF;
  84.         
  85.         if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  86.             myNumToolboxTraps = 0x0200;
  87.         else
  88.             myNumToolboxTraps = 0x0400;
  89.             
  90.         if (theTrapWord >= myNumToolboxTraps)
  91.             theTrapWord = _Unimplemented;
  92.     }
  93.  
  94.     return(NGetTrapAddress(theTrapWord, myTrapType) != NGetTrapAddress(_Unimplemented, ToolTrap));
  95. }
  96. #endif
  97.  
  98.  
  99. //////////
  100. //
  101. // QTVRUtils_IsQTVRMgrInstalled
  102. // Is the QuickTime VR Manager installed?
  103. //
  104. //////////
  105.  
  106. Boolean QTVRUtils_IsQTVRMgrInstalled (void) 
  107. {
  108.     Boolean     myQTVRAvail = false;
  109.     long        myAttrs;
  110.     OSErr         myErr = noErr;
  111.  
  112.     myErr = Gestalt(gestaltQTVRMgrAttr, &myAttrs);
  113.     if (myErr == noErr)
  114.         if (myAttrs & (1L << gestaltQTVRMgrPresent))
  115.             myQTVRAvail = true;
  116.  
  117.     return(myQTVRAvail);
  118. }
  119.  
  120.  
  121. //////////
  122. //
  123. // QTVRUtils_GetQTVRVersion
  124. // Get the version of the QuickTime VR Manager installed.
  125. //
  126. // The low-order word of the returned long integer contains the version number,
  127. // so you can test a version like this:
  128. //
  129. //        if (QTVRUtils_GetQTVRVersion() < 0x0210)        // we require QTVR 2.1 or greater
  130. //            return;
  131. //
  132. //////////
  133.  
  134. long QTVRUtils_GetQTVRVersion (void)
  135. {
  136.     long         myVersion = 0L;
  137.     OSErr         myErr = noErr;
  138.  
  139.     myErr = Gestalt(gestaltQTVRMgrVers, &myVersion);
  140.     if (myErr == noErr)
  141.         return(myVersion);
  142.     else
  143.         return(0L);
  144. }
  145.  
  146.  
  147. //////////
  148. //
  149. // QTVRUtils_GetControllerType
  150. // Get the controller type of the specified movie.
  151. //
  152. //////////
  153.  
  154. OSType QTVRUtils_GetControllerType (Movie theMovie) 
  155. {
  156.     UserData        myUserData;
  157.     OSType            myType = kQTVRUnknownType;
  158.     
  159.     // make sure we've got a movie
  160.     if (theMovie == NULL)
  161.         return(myType);
  162.         
  163.     myUserData = GetMovieUserData(theMovie);
  164.     if (myUserData != NULL)
  165.         GetUserDataItem(myUserData, &myType, sizeof(myType), kQTControllerType, 0);
  166.     
  167.     return(EndianU32_BtoN(myType));
  168. }
  169.  
  170.  
  171. //////////
  172. //
  173. // QTVRUtils_SetControllerType
  174. // Set the controller type of the specified movie.
  175. //
  176. // This function adds an item to the movie's user data;
  177. // the updated user data is written to the movie file when the movie is next updated
  178. // (by calling AddMovieResource or UpdateMovieResource).
  179. //
  180. //////////
  181.  
  182. OSErr QTVRUtils_SetControllerType (Movie theMovie, OSType theType)
  183. {
  184.     UserData        myUserData;
  185.     OSErr            myErr = noErr;
  186.  
  187.     // make sure we've got a movie
  188.     if (theMovie == NULL)
  189.         return(paramErr);
  190.         
  191.     // get the movie's user data list
  192.     myUserData = GetMovieUserData(theMovie);
  193.     if (myUserData == NULL)
  194.         return(paramErr);
  195.     
  196.     theType = EndianU32_NtoB(theType);
  197.     myErr = SetUserDataItem(myUserData, &theType, sizeof(theType), kQTControllerType, 0);
  198.  
  199.     return(myErr);
  200. }
  201.  
  202.  
  203. //////////
  204. //
  205. // QTVRUtils_IsQTVRMovie
  206. // Is the specified movie a QTVR movie?
  207. //
  208. // WARNING: This function is intended for use ONLY when you want to determine if you've got a QTVR movie
  209. // but you don't want to use the QuickTime VR API (perhaps QTVR isn't installed...). The preferred way to
  210. // determine if a movie is a QTVR movie is to call QTVRGetQTVRTrack and then QTVRGetQTVRInstance; if you
  211. // get back a non-NULL instance, you've got a VR movie.
  212. //
  213. //////////
  214.  
  215. Boolean QTVRUtils_IsQTVRMovie (Movie theMovie) 
  216. {
  217.     Boolean            myIsQTVRMovie = false;
  218.     OSType            myType;
  219.     
  220.     // QTVR movies have a special piece of user data identifying the movie controller type
  221.     myType = QTVRUtils_GetControllerType(theMovie);
  222.     
  223.     if ((myType == kQTVRQTVRType) || (myType == kQTVROldPanoType) || (myType == kQTVROldObjectType))
  224.         myIsQTVRMovie = true; 
  225.         
  226.     return(myIsQTVRMovie);
  227. }
  228.  
  229.  
  230. //////////
  231. //
  232. // QTVRUtils_Is20QTVRMovie
  233. // Is the specified QTVR movie version 2.0 or greater?
  234. //
  235. //////////
  236.  
  237. Boolean QTVRUtils_Is20QTVRMovie (Movie theMovie) 
  238. {
  239.     Boolean            myIs20QTVRMovie = false;
  240.     OSType            myType;
  241.     
  242.     // QTVR movies have a special piece of user data identifying the movie controller type
  243.     myType = QTVRUtils_GetControllerType(theMovie);
  244.     
  245.     if (myType == kQTVRQTVRType)
  246.         myIs20QTVRMovie = true; 
  247.         
  248.     return(myIs20QTVRMovie);
  249. }
  250.  
  251.  
  252. //////////
  253. //
  254. // QTVRUtils_IsTranslateAvailable
  255. // Is translation currently enabled for the specified object node?
  256. //
  257. //////////
  258.  
  259. Boolean QTVRUtils_IsTranslateAvailable (QTVRInstance theInstance) 
  260. {
  261.     Boolean        myState;
  262.     
  263.     QTVRGetControlSetting(theInstance, kQTVRTranslation, &myState);
  264.     return(myState);
  265. }
  266.  
  267.  
  268. //////////
  269. //
  270. // QTVRUtils_IsZoomAvailable
  271. // Is zooming currently enabled for the specified object node?
  272. //
  273. //////////
  274.  
  275. Boolean QTVRUtils_IsZoomAvailable (QTVRInstance theInstance) 
  276. {
  277.     Boolean        myState;
  278.     
  279.     QTVRGetControlSetting(theInstance, kQTVRCanZoom, &myState);
  280.     return(myState);
  281. }
  282.  
  283.  
  284. //////////
  285. //
  286. // QTVRUtils_IsPanoNode
  287. // Is the specified node a panoramic node?
  288. //
  289. //////////
  290.  
  291. Boolean QTVRUtils_IsPanoNode (QTVRInstance theInstance) 
  292. {
  293.     return(QTVRGetNodeType(theInstance, kQTVRCurrentNode) == kQTVRPanoramaType);
  294. }
  295.  
  296.  
  297. //////////
  298. //
  299. // QTVRUtils_IsObjectNode
  300. // Is the specified node an object node?
  301. //
  302. //////////
  303.  
  304. Boolean QTVRUtils_IsObjectNode (QTVRInstance theInstance) 
  305. {
  306.     return(QTVRGetNodeType(theInstance, kQTVRCurrentNode) == kQTVRObjectType);
  307. }
  308.  
  309.  
  310. //////////
  311. //
  312. // QTVRUtils_IsHotSpotInNode
  313. // Does the specified node contain at least one hot spot (whether visible, enabled, or whatever)?
  314. //
  315. // NOTE: This is not an easy function to implement using just the QTVR 2.1 API. We do have our own
  316. // utility QTVRUtils_GetHotSpotCount, but that function returns the number of hot spot information atoms
  317. // in the node, which is not (necessarily) the number of hot spot regions in the hot spot image track.
  318. // For panoramas, we could check to see if the panorama sample atom structure contains a reference
  319. // to a hot spot image track; if it does, we'd blindly assume that that track isn't empty. For objects,
  320. // we'll have to rely on QTVRUtils_GetHotSpotCount. So it goes....
  321. //
  322. // In an ideal world, there would be a hot spot information atom for each and every hot spot region in
  323. // the hot spot image track, in which case we could be happier using QTVRUtils_GetHotSpotCount.
  324. //
  325. //////////
  326.  
  327. Boolean QTVRUtils_IsHotSpotInNode (QTVRInstance theInstance) 
  328. {
  329.     return(QTVRUtils_GetHotSpotCount(theInstance, QTVRGetCurrentNodeID(theInstance), NULL) > 0);
  330. }
  331.  
  332.  
  333. //////////
  334. //
  335. // QTVRUtils_IsMultiNode
  336. // Does the specified QuickTime VR instance contain more than one node?
  337. //
  338. //////////
  339.  
  340. Boolean QTVRUtils_IsMultiNode (QTVRInstance theInstance) 
  341. {
  342.     return(QTVRUtils_GetNodeCount(theInstance) > (UInt32)1);
  343. }
  344.  
  345.  
  346. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  347. //
  348. // Controller bar utilities.
  349. //
  350. // Use these functions to manipulate the controller bar, its buttons, and the help text displayed in it.
  351. //
  352. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  353.  
  354. //////////
  355. //
  356. // QTVRUtils_IsControllerBarVisible
  357. // Is the controller bar currently visible?
  358. //
  359. //////////
  360.  
  361. Boolean QTVRUtils_IsControllerBarVisible (MovieController theMC) 
  362. {
  363.     return((Boolean)MCGetVisible(theMC));
  364. }
  365.  
  366.  
  367. //////////
  368. //
  369. // QTVRUtils_GetControllerBarHeight
  370. // Return the height of the controller bar displayed by the movie controller.
  371. //
  372. // Note that MCGetControllerBoundsRect returns rectangle of bar and movie, if attached;
  373. // so we need to unattach the controller bar first.
  374. //
  375. //////////
  376.  
  377. short QTVRUtils_GetControllerBarHeight (MovieController theMC) 
  378. {
  379.     Boolean        wasAttached = false;
  380.     Rect        myRect;
  381.     short        myHeight = 0;
  382.     
  383.     // if the controller bar is attached, detach it (and remember we did so)
  384.     if (MCIsControllerAttached(theMC) == 1) {
  385.         wasAttached = true;
  386.         MCSetControllerAttached(theMC, false);
  387.     }
  388.     
  389.     // get the rectangle of the controller
  390.     MCGetControllerBoundsRect(theMC, &myRect);
  391.     myHeight = myRect.bottom - myRect.top;
  392.     
  393.     // now reattach the controller bar, if it was originally attached
  394.     if (wasAttached)
  395.         MCSetControllerAttached(theMC, true);
  396.     
  397.     return(myHeight);
  398. }
  399.  
  400.  
  401. //////////
  402. //
  403. // QTVRUtils_HideControllerBar
  404. // Hide the controller bar provided by the movie controller.
  405. //
  406. //////////
  407.  
  408. void QTVRUtils_HideControllerBar (MovieController theMC) 
  409. {
  410.     MCSetVisible(theMC, false);
  411. }
  412.  
  413.  
  414. //////////
  415. //
  416. // QTVRUtils_ShowControllerBar
  417. // Show the controller bar provided by the movie controller.
  418. //
  419. //////////
  420.  
  421. void QTVRUtils_ShowControllerBar (MovieController theMC) 
  422. {
  423.     MCSetVisible(theMC, true);
  424. }
  425.  
  426.  
  427. //////////
  428. //
  429. // QTVRUtils_ToggleControllerBar
  430. // Toggle the state of the controller bar provided by the movie controller.
  431. //
  432. //////////
  433.  
  434. void QTVRUtils_ToggleControllerBar (MovieController theMC) 
  435. {
  436.     if (QTVRUtils_IsControllerBarVisible(theMC))
  437.         QTVRUtils_HideControllerBar(theMC);
  438.     else
  439.         QTVRUtils_ShowControllerBar(theMC);
  440. }
  441.  
  442.  
  443. //////////
  444. //
  445. // QTVRUtils_HideControllerButton
  446. // Hide the specified button in the controller bar.
  447. //
  448. // Some explanation is probably useful here: the first thing to understand is that every VR movie has 
  449. // TWO sets of movie controller flags: (1) a set of "control flags" and (2) a set of "explicit flags".
  450. //
  451. // The control flags work as documented in IM: QuickTime Components (pp. 2-20f) and in VRPWQTVR2.0 (pp. 2-23f):
  452. // if a bit in the set of control flags is set (that is, equal to 1), then the associated action or property is
  453. // enabled. For instance, bit 17 (mcFlagQTVRSuppressZoomBtns) means to suppress the zoom buttons. So, if that
  454. // bit is set in a VR movie's control flags, the zoom buttons are NOT displayed. If that bit is clear, the zoom
  455. // buttons are displayed.
  456. //
  457. // However, the QuickTime VR movie controller sometimes suppresses buttons even when those buttons 
  458. // have not been explicitly suppressed in the control flags. For example, if a particular VR movie does not
  459. // contain a sound track, then the movie controller automatically suppresses the speaker/volume button. Likewise,
  460. // if a movie does contain a sound track, then the speaker/volume button is automatically displayed, again without
  461. // regard to the actual value of bit 17 in the control flags.
  462. //
  463. // This might not be what you'd like to happen. For instance, if your application is playing a sound that it
  464. // loaded from a sound resource, you might want the user to be able to adjust the sound's volume using the volume
  465. // control. To do that, you need a way to *force* the speaker/volume button to appear. For this reason, the
  466. // explicit flags were introduced.
  467. //
  468. // The explicit flags indicate which bits in the control flags are to be used explicitly (that is, taken at
  469. // face value). If a certain bit is set in a movie's explicit flags, then the corresponding bit in the control
  470. // flags is interpreted as the desired setting for the feature (and the movie controller will not attempt to
  471. // do anything "clever"). In other words, if bit 17 is set in a movie's explicit flags and bit 17 is clear in
  472. // that movie's control flags, then the zoom buttons are displayed. Similarly, if bit 2 is set in a movie's 
  473. // explicit flags and bit 2 is clear in that movie's control flags, then the speaker/volume button is displayed,
  474. // whether or not the movie contains a sound track.
  475. //
  476. // The final thing to understand: to get or set a bit in a movie's explicit flags, you must set the flag 
  477. // mcFlagQTVRExplicitFlagSet in your call to mcActionGetFlags or mcActionSetFlags. To get or set a bit in a 
  478. // movie's control flags, you must clear the flag mcFlagQTVRExplicitFlagSet in your call to mcActionGetFlags 
  479. // or mcActionSetFlags. Note that when you use the defined constants to set values in the explicit flags, the 
  480. // constant names might be confusing. For instance, setting the bit mcFlagSuppressSpeakerButton in a movie's
  481. // explicit flags doesn't cause the speaker to be suppressed; it just means: "use the actual value of the
  482. // mcFlagSuppressSpeakerButton bit in the control flags".
  483. //
  484. // Whew! Any questions? Okay, then now you'll understand how to hide or show a button in the controller bar:
  485. // set the appropriate explicit flag to 1 and set the corresponding control flag to the desired value. And
  486. // you'll understand how to let the movie controller do its "clever" work: clear the appropriate explicit flag.
  487. //
  488. //////////
  489.  
  490. void QTVRUtils_HideControllerButton (MovieController theMC, long theButton) 
  491. {
  492.     long    myControllerFlags;
  493.     
  494.     // get the current explicit flags and set the explicit flag for the specified button
  495.     myControllerFlags = mcFlagQTVRExplicitFlagSet;
  496.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  497.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) | mcFlagQTVRExplicitFlagSet));
  498.     
  499.     // get the current control flags and set the suppress flag for the specified button
  500.     myControllerFlags = 0;
  501.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  502.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) & ~mcFlagQTVRExplicitFlagSet));
  503. }
  504.  
  505.  
  506. //////////
  507. //
  508. // QTVRUtils_ShowControllerButton
  509. // Show the specified button in the controller bar.
  510. //
  511. //////////
  512.  
  513. void QTVRUtils_ShowControllerButton (MovieController theMC, long theButton) 
  514. {
  515.     long    myControllerFlags;
  516.     
  517.     // get the current explicit flags and set the explicit flag for the specified button
  518.     myControllerFlags = mcFlagQTVRExplicitFlagSet;
  519.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  520.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) | mcFlagQTVRExplicitFlagSet));
  521.     
  522.     // get the current control flags and clear the suppress flag for the specified button
  523.     myControllerFlags = 0;
  524.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  525.     MCDoAction(theMC, mcActionSetFlags, (void *)(myControllerFlags & ~theButton & ~mcFlagQTVRExplicitFlagSet));
  526. }
  527.  
  528.  
  529. //////////
  530. //
  531. // QTVRUtils_ToggleControllerButton
  532. // Toggle the state of the specified button in the controller bar.
  533. //
  534. //////////
  535.  
  536. void QTVRUtils_ToggleControllerButton (MovieController theMC, long theButton) 
  537. {
  538.     long    myControllerFlags;
  539.     
  540.     // get the current control flags and toggle the suppress flag for the specified button
  541.     myControllerFlags = 0;
  542.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  543.     
  544.     if (myControllerFlags & theButton)                // if the button is currently suppressed...
  545.         QTVRUtils_ShowControllerButton(theMC, theButton);
  546.     else
  547.         QTVRUtils_HideControllerButton(theMC, theButton);
  548. }
  549.  
  550.  
  551. //////////
  552. //
  553. // QTVRUtils_ResetControllerButton
  554. // Remove any explicit setting of the specified button in the controller bar.
  555. // (This allows the QuickTime VR movie controller to be as clever as it knows how to be.)
  556. //
  557. //////////
  558.  
  559. void QTVRUtils_ResetControllerButton (MovieController theMC, long theButton) 
  560. {
  561.     long    myControllerFlags = mcFlagQTVRExplicitFlagSet;
  562.     
  563.     // get the current explicit flags and clear the explicit flag for the specified button
  564.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  565.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) & ~mcFlagQTVRExplicitFlagSet));
  566. }
  567.  
  568.  
  569. //////////
  570. //
  571. // QTVRUtils_IsControllerButtonVisible
  572. // Is the specified button in the controller bar currently visible?
  573. //
  574. //////////
  575.  
  576. Boolean QTVRUtils_IsControllerButtonVisible (MovieController theMC, long theButton) 
  577. {
  578.     long        myControllerFlags;
  579.  
  580.     // get the current control flags
  581.     myControllerFlags = 0;
  582.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  583.  
  584.     // the speaker button requires some additional logic, because the QTVR movie controller treats it special;
  585.     // be advised that that controller's special behavior could change in the future,
  586.     // so you might need to tweak this code
  587.     if (theButton == mcFlagSuppressSpeakerButton) {
  588.         long    myExplicitFlags;
  589.         
  590.         // get the current explicit flags
  591.         myExplicitFlags = mcFlagQTVRExplicitFlagSet;
  592.         MCDoAction(theMC, mcActionGetFlags, &myExplicitFlags);
  593.     
  594.         // the speaker button is not showing if the movie has no sound track and the explicit flag is not set
  595.         if (!QTUtils_MovieHasSoundTrack(MCGetMovie(theMC)) && !(myExplicitFlags & theButton))
  596.             return(false);
  597.     }
  598.     
  599.     // examine the suppress flag for the specified button
  600.     if (myControllerFlags & theButton)                // if the button is currently suppressed...
  601.         return(false);
  602.     else
  603.         return(true);
  604. }
  605.  
  606.  
  607. //////////
  608. //
  609. // QTVRUtils_HideHotSpotNames
  610. // Disable the displaying of hot spot names in the controller bar.
  611. //
  612. //////////
  613.  
  614. void QTVRUtils_HideHotSpotNames (MovieController theMC) 
  615. {
  616.     QTVRUtils_HideControllerButton(theMC, kQTVRHotSpotNames);
  617. }
  618.  
  619.  
  620. //////////
  621. //
  622. // QTVRUtils_ShowHotSpotNames
  623. // Enable the displaying of hot spot names in the controller bar.
  624. //
  625. //////////
  626.  
  627. void QTVRUtils_ShowHotSpotNames (MovieController theMC) 
  628. {
  629.     QTVRUtils_ShowControllerButton(theMC, kQTVRHotSpotNames);
  630. }
  631.  
  632.  
  633. //////////
  634. //
  635. // QTVRUtils_ToggleHotSpotNames
  636. // Toggle the displaying of hot spot names in the controller bar.
  637. //
  638. //////////
  639.  
  640. void QTVRUtils_ToggleHotSpotNames (MovieController theMC) 
  641. {
  642.     QTVRUtils_ToggleControllerButton(theMC, kQTVRHotSpotNames);
  643. }
  644.  
  645.  
  646. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  647. //
  648. // File format utilities.
  649. //
  650. // Use these functions to read information from QuickTime VR files that's not accessible using the API.
  651. // Throughout, we assume that we're dealing with format 2.0 files. We begin with a series of functions that
  652. // return a pointer to the data in an atom (QTVRUtils_Get*AtomData); you probably won't use these functions
  653. // directly.
  654. //
  655. // Keep in mind that data stored in QuickTime atoms is big-endian. We'll need to convert any multi-byte data
  656. // that we read from an atom to native format before we use it.
  657. //
  658. // Note that these file format utilities are all Getters. As yet, no Setters. Perhaps later?
  659. //
  660. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  661.  
  662. //////////
  663. //
  664. // QTVRUtils_GetVRWorldHeaderAtomData
  665. // Get a pointer to the VR world header atom data in a QTVR movie.
  666. //
  667. //////////
  668.  
  669. OSErr QTVRUtils_GetVRWorldHeaderAtomData (QTVRInstance theInstance, QTVRWorldHeaderAtomPtr theVRWorldHdrAtomPtr)
  670. {
  671.     QTAtomContainer            myVRWorld;
  672.     QTAtom                    myAtom;
  673.     OSErr                    myErr = noErr;
  674.         
  675.     // get the VR world
  676.     myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  677.     if (myErr != noErr)
  678.         return(myErr);
  679.     
  680.     // get the single VR world header atom in the VR world
  681.     myAtom = QTFindChildByIndex(myVRWorld, kParentAtomIsContainer, kQTVRWorldHeaderAtomType, 1, NULL);
  682.     if (myAtom != 0)
  683.         myErr = QTCopyAtomDataToPtr(myVRWorld, myAtom, false, sizeof(QTVRWorldHeaderAtom), theVRWorldHdrAtomPtr, NULL);
  684.     else 
  685.         myErr = cannotFindAtomErr;
  686.     
  687.     QTDisposeAtomContainer(myVRWorld);
  688.     return(myErr);
  689. }
  690.  
  691.  
  692. //////////
  693. //
  694. // QTVRUtils_GetNodeHeaderAtomData
  695. // Get a pointer to the node header atom data for the node having the specified node ID.
  696. //
  697. //////////
  698.  
  699. OSErr QTVRUtils_GetNodeHeaderAtomData (QTVRInstance theInstance, UInt32 theNodeID, QTVRNodeHeaderAtomPtr theNodeHdrPtr)
  700. {
  701.     QTAtomContainer            myNodeInfo;
  702.     QTAtom                    myAtom;
  703.     OSErr                    myErr = noErr;
  704.         
  705.     // get the node information atom container for the specified node
  706.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  707.     if (myErr != noErr)
  708.         return(myErr);
  709.     
  710.     // get the single node header atom in the node information atom container
  711.     myAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRNodeHeaderAtomType, 1, NULL);
  712.     if (myAtom != 0)
  713.         myErr = QTCopyAtomDataToPtr(myNodeInfo, myAtom, false, sizeof(QTVRNodeHeaderAtom), theNodeHdrPtr, NULL);
  714.     else 
  715.         myErr = cannotFindAtomErr;
  716.  
  717.     QTDisposeAtomContainer(myNodeInfo);
  718.     return(myErr);
  719. }
  720.  
  721.  
  722. //////////
  723. //
  724. // QTVRUtils_GetHotSpotAtomData
  725. // Get a pointer to the hot spot atom data for hot spot having the specified hot spot ID in the specified node.
  726. //
  727. //////////
  728.  
  729. OSErr QTVRUtils_GetHotSpotAtomData (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID, QTVRHotSpotInfoAtomPtr theHotSpotInfoPtr)
  730. {
  731.     QTAtomContainer            myNodeInfo;
  732.     QTAtom                    myHSParentAtom;
  733.     OSErr                    myErr = noErr;
  734.         
  735.     // (1) the node information atom container contains a *hot spot parent atom*;
  736.     // (2) the hot spot parent atom contains one or more *hot spot atoms*;
  737.     // (3) the hot spot atom contains two children, a *general hot spot information atom*
  738.     //     and a *specific hot spot information atom*.
  739.     // We want to return a pointer to the general hot spot information atom data.
  740.  
  741.     // get the node information atom container for the specified node
  742.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  743.     if (myErr != noErr)
  744.         return(myErr);
  745.     
  746.     // get the single hot spot parent atom in the node information atom container
  747.     myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  748.     if (myHSParentAtom != 0) {
  749.         QTAtom                myHSAtom;
  750.         
  751.         // get the hot spot atom whose atom ID is the specified hot spot ID
  752.         myHSAtom = QTFindChildByID(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, theHotSpotID, NULL);
  753.         if (myHSAtom != 0) {
  754.             QTAtom            myAtom;
  755.             
  756.             // get the single hot spot information atom in the hot spot atom
  757.             myAtom = QTFindChildByIndex(myNodeInfo, myHSAtom, kQTVRHotSpotInfoAtomType, 1, NULL);
  758.             if (myAtom != 0) {
  759.                 myErr = QTCopyAtomDataToPtr(myNodeInfo, myAtom, false, sizeof(QTVRHotSpotInfoAtom), theHotSpotInfoPtr, NULL);
  760.             }
  761.         } else {
  762.             myErr = cannotFindAtomErr;
  763.         }
  764.     } else {
  765.         myErr = cannotFindAtomErr;
  766.     }
  767.  
  768.     QTDisposeAtomContainer(myNodeInfo);
  769.     return(myErr);
  770. }
  771.  
  772.  
  773. //////////
  774. //
  775. // QTVRUtils_GetStringFromAtom
  776. // Get the string data from the string atom having the specified ID in the specified atom container.
  777. //
  778. // We use a different strategy here, since we don't know the size of the string data in advance.
  779. //
  780. //////////
  781.  
  782. char *QTVRUtils_GetStringFromAtom (QTAtomContainer theContainer, QTAtom theParent, QTAtomID theID)
  783. {
  784.     QTVRStringAtomPtr    myStringAtomPtr = NULL;
  785.     QTAtom                myNameAtom;
  786.     char                *myString = NULL;
  787.      OSErr                myErr = noErr;
  788.  
  789.     if (theContainer == NULL)
  790.         return(myString);
  791.         
  792.     QTLockContainer(theContainer);
  793.     
  794.     myNameAtom = QTFindChildByID(theContainer, theParent, kQTVRStringAtomType, theID, NULL);
  795.     if (myNameAtom != 0) {
  796.         myErr = QTGetAtomDataPtr(theContainer, myNameAtom, NULL, (Ptr *)&myStringAtomPtr);
  797.         if ((myErr == noErr) && (myStringAtomPtr != NULL)) {
  798.             UInt16        myLength;
  799.                 
  800.             myLength = EndianU16_BtoN(myStringAtomPtr->stringLength);
  801.             if (myLength > 0) {
  802.                 myString = malloc(myLength + 1);
  803.                 if (myString != NULL) {
  804.                     memcpy(myString, myStringAtomPtr->theString, myLength);
  805.                     myString[myLength] = '\0';
  806.                 }
  807.             }            
  808.         }
  809.     }
  810.     
  811.     QTUnlockContainer(theContainer);
  812.     return(myString);
  813. }
  814.  
  815.  
  816. //////////
  817. //
  818. // QTVRUtils_AddStr255ToAtomContainer
  819. // Add a Pascal string to the specified atom container; return (through theID) the ID of the new string atom.
  820. //
  821. //////////
  822.  
  823. OSErr QTVRUtils_AddStr255ToAtomContainer (QTAtomContainer theContainer, QTAtom theParent, Str255 theString, QTAtomID *theID)
  824. {
  825.     OSErr                    myErr = noErr;
  826.  
  827.     *theID = 0;                // initialize the returned atom ID
  828.     
  829.     if ((theContainer == NULL) || (theParent == 0))
  830.         return(paramErr);
  831.         
  832.     if (theString[0] != 0) {
  833.         QTAtom                myStringAtom;
  834.         UInt16                mySize;
  835.         QTVRStringAtomPtr    myStringAtomPtr = NULL;
  836.         
  837.         mySize = sizeof(QTVRStringAtom) - 4 + theString[0] + 1;
  838.         myStringAtomPtr = (QTVRStringAtomPtr)NewPtrClear(mySize);
  839.         
  840.         if (myStringAtomPtr != NULL) {
  841.             myStringAtomPtr->stringUsage = EndianU16_NtoB(1);
  842.             myStringAtomPtr->stringLength = EndianU16_NtoB(theString[0]);
  843.             BlockMove(theString + 1, myStringAtomPtr->theString, theString[0]);
  844.             myStringAtomPtr->theString[theString[0]] = '\0';
  845.             myErr = QTInsertChild(theContainer, theParent, kQTVRStringAtomType, 0, 0, mySize, (Ptr)myStringAtomPtr, &myStringAtom);
  846.             DisposePtr((Ptr)myStringAtomPtr);
  847.             
  848.             if (myErr == noErr)
  849.                 QTGetAtomTypeAndID(theContainer, myStringAtom, NULL, theID);
  850.         }
  851.     }
  852.     
  853.     return(myErr);
  854. }
  855.  
  856.  
  857. //////////
  858. //
  859. // QTVRUtils_GetDefaultNodeID
  860. // Get the ID of the default node in a QTVR movie.
  861. //
  862. //////////
  863.  
  864. UInt32 QTVRUtils_GetDefaultNodeID (QTVRInstance theInstance)
  865. {
  866.     QTVRWorldHeaderAtom         myVRWorldHeader;
  867.     UInt32                    myNodeID = kQTVRCurrentNode;
  868.     OSErr                    myErr = noErr;
  869.         
  870.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  871.     if (myErr == noErr)
  872.         myNodeID = EndianU32_BtoN(myVRWorldHeader.defaultNodeID);
  873.  
  874.     return(myNodeID);
  875. }
  876.  
  877.  
  878. //////////
  879. //
  880. // QTVRUtils_GetSceneFlags
  881. // Get the set of flags associated with the VR scene.
  882. // (Currently these flags are undefined, however.)
  883. //
  884. //////////
  885.  
  886. UInt32 QTVRUtils_GetSceneFlags (QTVRInstance theInstance)
  887. {
  888.     QTVRWorldHeaderAtom         myVRWorldHeader;
  889.     UInt32                    myFlags = 0L;
  890.     OSErr                    myErr;
  891.         
  892.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  893.     if (myErr == noErr)
  894.         myFlags = EndianU32_BtoN(myVRWorldHeader.vrWorldFlags);
  895.  
  896.     return(myFlags);
  897. }
  898.  
  899.  
  900. //////////
  901. //
  902. // QTVRUtils_GetSceneName
  903. // Get the name of the VR scene.
  904. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  905. //
  906. //////////
  907.  
  908. char *QTVRUtils_GetSceneName (QTVRInstance theInstance)
  909. {
  910.     QTVRWorldHeaderAtom             myVRWorldHeader;
  911.     char                        *mySceneName = NULL;
  912.     OSErr                        myErr = noErr;
  913.         
  914.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  915.     if (myErr == noErr) {
  916.         QTAtomID                myNameAtomID;
  917.         
  918.         // get the atom ID of the name string atom
  919.         myNameAtomID = EndianU32_BtoN(myVRWorldHeader.nameAtomID);
  920.         
  921.         if (myNameAtomID != 0) {
  922.             QTAtomContainer        myVRWorld;
  923.             
  924.             // the string atom containing the name of the scene is a *sibling* of the VR world header atom
  925.             myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  926.             if (myErr == noErr)
  927.                 mySceneName = QTVRUtils_GetStringFromAtom(myVRWorld, kParentAtomIsContainer, myNameAtomID);
  928.             
  929.             QTDisposeAtomContainer(myVRWorld);
  930.         }
  931.     }
  932.  
  933.     return(mySceneName);
  934. }
  935.  
  936.  
  937. //////////
  938. //
  939. // QTVRUtils_GetNodeCount
  940. // Get the number of nodes in a QTVR movie.
  941. //
  942. //////////
  943.  
  944. UInt32 QTVRUtils_GetNodeCount (QTVRInstance theInstance)
  945. {
  946.     QTAtomContainer            myVRWorld;
  947.     QTAtom                    myNodeParentAtom;
  948.     UInt32                    myNumNodes = 0;
  949.     OSErr                    myErr = noErr;
  950.  
  951.     // get the VR world
  952.     myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  953.     if (myErr != noErr)
  954.         return(myNumNodes);
  955.  
  956.     // get the node parent atom, whose children contain info about all nodes in the scene
  957.     myNodeParentAtom = QTFindChildByIndex(myVRWorld, kParentAtomIsContainer, kQTVRNodeParentAtomType, 1, NULL);
  958.     if (myNodeParentAtom != 0) {
  959.         // now count the node ID children of the node parent atom, which is the number of nodes in the scene
  960.         myNumNodes = QTCountChildrenOfType(myVRWorld, myNodeParentAtom, kQTVRNodeIDAtomType);
  961.     }    
  962.  
  963.     QTDisposeAtomContainer(myVRWorld);
  964.     
  965.     return(myNumNodes);
  966. }
  967.  
  968.  
  969. //////////
  970. //
  971. // QTVRUtils_GetNodeType
  972. // Get the type of the node with the specified ID.
  973. //
  974. // NOTE: This function is redundant, given QTVRGetNodeType; it's included here for illustrative purposes only.
  975. //
  976. //////////
  977.  
  978. OSErr QTVRUtils_GetNodeType (QTVRInstance theInstance, UInt32 theNodeID, OSType *theNodeType)
  979. {
  980.     QTVRNodeHeaderAtom        myNodeHeader;
  981.     OSErr                    myErr = noErr;
  982.  
  983.     // make sure we always return some meaningful value
  984.     *theNodeType = kQTVRUnknownType;
  985.     
  986.     // get the node header atom data
  987.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  988.     if (myErr == noErr)
  989.         *theNodeType = EndianU32_BtoN(myNodeHeader.nodeType);
  990.         
  991.     return(myErr);
  992. }
  993.  
  994.  
  995. //////////
  996. //
  997. // QTVRUtils_GetNodeName
  998. // Get the name of the node with the specified ID.
  999. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1000. //
  1001. //////////
  1002.  
  1003. char *QTVRUtils_GetNodeName (QTVRInstance theInstance, UInt32 theNodeID)
  1004. {
  1005.     QTVRNodeHeaderAtom        myNodeHeader;
  1006.     char                    *myNodeName = NULL;
  1007.     OSErr                    myErr = noErr;
  1008.     
  1009.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  1010.     if (myErr == noErr) {
  1011.         QTAtomID                myNameAtomID;
  1012.         
  1013.         // get the atom ID of the name string atom
  1014.         myNameAtomID = EndianU32_BtoN(myNodeHeader.nameAtomID);
  1015.         
  1016.         if (myNameAtomID != 0) {
  1017.             QTAtomContainer        myNodeInfo;
  1018.             
  1019.             // the string atom containing the name of the node is a *sibling* of the node information atom
  1020.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  1021.             if (myErr == noErr)
  1022.                 myNodeName = QTVRUtils_GetStringFromAtom(myNodeInfo, kParentAtomIsContainer, myNameAtomID);
  1023.  
  1024.             QTDisposeAtomContainer(myNodeInfo);
  1025.         }
  1026.     }
  1027.     
  1028.     return(myNodeName);
  1029. }
  1030.  
  1031.  
  1032. //////////
  1033. //
  1034. // QTVRUtils_GetNodeComment
  1035. // Get the comment for the node with the specified ID.
  1036. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1037. //
  1038. //////////
  1039.  
  1040. char *QTVRUtils_GetNodeComment (QTVRInstance theInstance, UInt32 theNodeID)
  1041. {
  1042.     QTVRNodeHeaderAtom        myNodeHeader;
  1043.     char                    *myNodeCmt = NULL;
  1044.     OSErr                    myErr = noErr;
  1045.     
  1046.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  1047.     if (myErr == noErr) {
  1048.         QTAtomID                myCmtAtomID;
  1049.         
  1050.         // get the atom ID of the comment string atom
  1051.         myCmtAtomID = EndianU32_BtoN(myNodeHeader.commentAtomID);
  1052.         
  1053.         if (myCmtAtomID != 0) {
  1054.             QTAtomContainer        myNodeInfo;
  1055.             
  1056.             // the string atom containing the comment for the node is a *sibling* of the node information atom
  1057.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  1058.             if (myErr == noErr)
  1059.                 myNodeCmt = QTVRUtils_GetStringFromAtom(myNodeInfo, kParentAtomIsContainer, myCmtAtomID);
  1060.  
  1061.             QTDisposeAtomContainer(myNodeInfo);
  1062.         }
  1063.     }
  1064.     
  1065.     return(myNodeCmt);
  1066. }
  1067.  
  1068.  
  1069. //////////
  1070. //
  1071. // QTVRUtils_GetHotSpotCount
  1072. // Return the number of hot spots in the node with specified ID,
  1073. // and fill the specified handle with a list of the hot spot IDs.
  1074. //
  1075. // If theHotSpotIDs == NULL on entry, do not pass back the list of IDs.
  1076. //
  1077. // WARNING: This routine determines the number of hot spots by counting
  1078. // the hot spot atoms in a hot spot parent atom; this might not be
  1079. // the same as counting the number of regions in the hot spot image track.
  1080. // Sigh.
  1081. //
  1082. //////////
  1083.  
  1084. UInt32 QTVRUtils_GetHotSpotCount (QTVRInstance theInstance, UInt32 theNodeID, Handle theHotSpotIDs)
  1085. {
  1086.     QTAtomContainer            myNodeInfo;
  1087.     QTAtom                    myHSParentAtom = 0;
  1088.     UInt32                    myNumHotSpots = 0;
  1089.     OSErr                    myErr = noErr;
  1090.     
  1091.     // get the node information atom container for the current node
  1092.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  1093.     
  1094.     // get the hot spot parent atom
  1095.     if (myErr == noErr)
  1096.         myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  1097.         
  1098.     if (myHSParentAtom != 0) {
  1099.         SignedByte            myHState;
  1100.         Size                mySize;
  1101.  
  1102.         // get the number of hot spots in the current node
  1103.         myNumHotSpots = QTCountChildrenOfType(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType);
  1104.         
  1105.         // now pass back a list of the hot spot IDs;
  1106.         // if theHotSpotIDs is NULL on entry, we assume the caller doesn't want this information
  1107.         if (theHotSpotIDs != NULL) {
  1108.         
  1109.             // unlock the handle, if it's locked (so that we can resize it)
  1110.             myHState = HGetState(theHotSpotIDs);
  1111.             if (myHState & 0x80)            // 0x80 == the block-is-locked bit in the SignedByte returned by HGetState
  1112.                 HUnlock(theHotSpotIDs);
  1113.  
  1114.             // resize the handle to the appropriate size
  1115.             mySize = sizeof(UInt32) * myNumHotSpots;
  1116.             SetHandleSize(theHotSpotIDs, mySize);
  1117.             
  1118.             // restore the original handle state
  1119.             HSetState(theHotSpotIDs, myHState);
  1120.             
  1121.             // make sure we actually did resize the handle
  1122.             if (GetHandleSize(theHotSpotIDs) == mySize) {
  1123.                 short            myIndex;
  1124.                 QTAtom            myAtom;
  1125.                 QTAtomID        myID;
  1126.                 UInt32            *myIDPtr;
  1127.                 
  1128.                 myIDPtr = (UInt32 *)*theHotSpotIDs;
  1129.  
  1130.                 // loop thru all the hot spots to get their IDs
  1131.                 for (myIndex = 1; myIndex <= (short)myNumHotSpots; myIndex++) {
  1132.                     myAtom = QTFindChildByIndex(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, myIndex, &myID);
  1133.                     myIDPtr[myIndex - 1] = (UInt32)myID;
  1134.                 }
  1135.             }
  1136.         }
  1137.     }
  1138.     
  1139.     QTDisposeAtomContainer(myNodeInfo);
  1140.     return(myNumHotSpots);
  1141. }
  1142.  
  1143.  
  1144. //////////
  1145. //
  1146. // QTVRUtils_GetHotSpotIDByIndex
  1147. // Return the hot spot ID having the specified index in the list of hot spot IDs returned by QTVRUtils_GetHotSpotCount,
  1148. // or kQTVRUtils_InvalidHotSpotID if no such hot spot exists.
  1149. //
  1150. //////////
  1151.  
  1152. UInt32 QTVRUtils_GetHotSpotIDByIndex (QTVRInstance theInstance, Handle theHotSpotIDs, UInt32 theIndex)
  1153. {
  1154.     Size            mySize;
  1155.     UInt32            myID = kQTVRUtils_InvalidHotSpotID;
  1156.     UInt32            *myIDPtr;
  1157.                 
  1158.     // make sure the instance and hot spot list are non-NULL
  1159.     if ((theInstance == NULL) || (theHotSpotIDs == NULL))
  1160.         return(myID);
  1161.     
  1162.     // make sure that the index is valid    
  1163.     mySize = GetHandleSize(theHotSpotIDs);
  1164.     if (theIndex >= (mySize / sizeof(UInt32)))
  1165.         return(myID);
  1166.  
  1167.     myIDPtr = (UInt32 *)*theHotSpotIDs;
  1168.     myID = myIDPtr[theIndex];
  1169.     return(myID);
  1170. }
  1171.  
  1172.  
  1173. //////////
  1174. //
  1175. // QTVRUtils_GetHotSpotType
  1176. // Return the type of the hot spot having the specified hot spot ID in the specified node.
  1177. //
  1178. // NOTE: This function is semi-redundant, given QTVRGetHotSpotType; it's included here for illustrative purposes only.
  1179. // (Note, however, that QTVRGetHotSpotType returns types only for hot spots in the current node; here we do any node!)
  1180. //
  1181. //////////
  1182.  
  1183. OSErr QTVRUtils_GetHotSpotType (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID, OSType *theHotSpotType)
  1184. {
  1185.     QTVRHotSpotInfoAtom        myHotSpotAtomData;
  1186.     OSErr                    myErr = noErr;
  1187.     
  1188.     // make sure we always return some meaningful value
  1189.     *theHotSpotType = kQTVRHotSpotUndefinedType;
  1190.     
  1191.     // get the hot spot information atom data
  1192.     myErr = QTVRUtils_GetHotSpotAtomData(theInstance, theNodeID, theHotSpotID, &myHotSpotAtomData);
  1193.     if (myErr == noErr)
  1194.         *theHotSpotType = EndianU32_BtoN(myHotSpotAtomData.hotSpotType);        // return the hot spot type
  1195.     
  1196.     return(myErr);
  1197. }
  1198.  
  1199.  
  1200. //////////
  1201. //
  1202. // QTVRUtils_GetHotSpotName
  1203. // Return the name of the hot spot having the specified hot spot ID in the specified node.
  1204. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1205. //
  1206. //////////
  1207.  
  1208. char *QTVRUtils_GetHotSpotName (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID)
  1209. {
  1210.     QTVRHotSpotInfoAtom        myHotSpotAtomData;
  1211.     char                    *myHotSpotName = NULL;
  1212.     OSErr                    myErr = noErr;
  1213.     
  1214.     // get the hot spot information atom data
  1215.     myErr = QTVRUtils_GetHotSpotAtomData(theInstance, theNodeID, theHotSpotID, &myHotSpotAtomData);
  1216.     if (myErr == noErr) {
  1217.         QTAtomID                myNameAtomID;
  1218.         
  1219.         // get the atom ID of the name string atom
  1220.         myNameAtomID = EndianU32_BtoN(myHotSpotAtomData.nameAtomID);
  1221.         
  1222.         if (myNameAtomID != 0) {
  1223.             QTAtomContainer        myNodeInfo;
  1224.             QTAtom                myHSParentAtom;
  1225.             QTAtom                myHSAtom;
  1226.             QTAtom                myNameAtom = 0;
  1227.             
  1228.             // version 2.0 documentation says that the hot spot name is contained in a string atom
  1229.             // that is a sibling of the hot spot atom (that is, a child of the hot spot parent atom);
  1230.             // some other documents indicate that a string atom is always a sibling of the atom that
  1231.             // contains the reference (in this case, a sibling of the hot spot information atom, and
  1232.             // hence a child of the hot spot atom); we will look first in the hot spot atom and then
  1233.             // in the hot spot parent atom. The version 2.1 documentation corrects the earlier error.
  1234.             // Mea culpa!
  1235.  
  1236.             // get the hot spot parent atom and the hot spot atom
  1237.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  1238.             if (myErr == noErr) {
  1239.                 myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  1240.                 if (myHSParentAtom != 0) {
  1241.                     myHSAtom = QTFindChildByID(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, theHotSpotID, NULL);
  1242.                     if (myHSAtom != 0) {
  1243.                         QTAtom    myParentAtom;
  1244.                         
  1245.                         // look for a string atom that is a child of the hot spot atom
  1246.                         myParentAtom = myHSAtom;
  1247.                         myNameAtom = QTFindChildByID(myNodeInfo, myParentAtom, kQTVRStringAtomType, theHotSpotID, NULL);
  1248.                         if (myNameAtom == 0) {
  1249.                             // no such atom in the hot spot atom; look in the hot spot parent atom
  1250.                             myParentAtom = myHSParentAtom;
  1251.                             myNameAtom = QTFindChildByID(myNodeInfo, myParentAtom, kQTVRStringAtomType, theHotSpotID, NULL);
  1252.                         }
  1253.                         
  1254.                         if (myNameAtom != 0)
  1255.                             myHotSpotName = QTVRUtils_GetStringFromAtom(myNodeInfo, myParentAtom, myNameAtomID);
  1256.                     }
  1257.                 }
  1258.             }
  1259.             
  1260.             QTDisposeAtomContainer(myNodeInfo);
  1261.         }
  1262.     }
  1263.  
  1264.     return(myHotSpotName);
  1265. }
  1266.  
  1267.  
  1268. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1269. //
  1270. // Miscellaneous utilities.
  1271. //
  1272. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1273.  
  1274.  
  1275. //////////
  1276. //
  1277. // QTVRUtils_Point3DToPanAngle
  1278. // Return the QTVR pan angle for a given QD3D point.
  1279. // 
  1280. //////////
  1281.  
  1282. float QTVRUtils_Point3DToPanAngle (float theX, float theY, float theZ)
  1283. {
  1284. #pragma unused(theY)
  1285.  
  1286.     float    myPan;
  1287.     
  1288.     if (theZ != 0.0) {
  1289.         // note that atan always returns angles in the range -╣/2 to ╣/2
  1290.         myPan = atan(theX / theZ);
  1291.         myPan = (theZ > 0) ? myPan + kVRPi : myPan;
  1292.     } else {
  1293.         myPan = (theX > 0) ? kVR3PiOver2 : kVRPiOver2;
  1294.     }
  1295.     
  1296.     // make sure myPan is positive
  1297.     while (myPan < 0.0)
  1298.         myPan += kVR2Pi;
  1299.  
  1300.     return(myPan);
  1301. }
  1302.  
  1303.  
  1304. //////////
  1305. //
  1306. // QTVRUtils_Point3DToTiltAngle
  1307. // Return the QTVR tilt angle for a given QD3D point.
  1308. // 
  1309. //////////
  1310.  
  1311. float QTVRUtils_Point3DToTiltAngle (float theX, float theY, float theZ)
  1312. {
  1313.     float            myTilt;
  1314.     float            myDistance;
  1315.     TQ3Point3D        myPoint;
  1316.     
  1317.     myPoint.x = theX;
  1318.     myPoint.y = theY;
  1319.     myPoint.z = theZ;
  1320.     
  1321.     myDistance = QTVRUtils_GetDistance(myPoint);
  1322.     if (myDistance != 0.0)
  1323.         myTilt = asin(theY / myDistance); 
  1324.     else
  1325.         myTilt = 0.0;
  1326.     
  1327.     return(myTilt);
  1328. }
  1329.  
  1330.  
  1331. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1332. //
  1333. // Node callback utilities.
  1334. //
  1335. // Use these to obtain standard behaviors when entering or exiting nodes.
  1336. //
  1337. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1338.  
  1339. //////////
  1340. //
  1341. // QTVRUtils_StandardEnteringNodeProc
  1342. // A standard procedure for entering a new node.
  1343. //
  1344. // This function performs actions that many applications will want done when entering a new node:
  1345. //    * display back button only if multinode movie
  1346. //    * display show-hot-spot button only if there are hotspots
  1347. //    * display the translate button only for object nodes that can translate
  1348. //    * (this space for rent)
  1349. //
  1350. //////////
  1351.  
  1352. PASCAL_RTN OSErr QTVRUtils_StandardEnteringNodeProc (QTVRInstance theInstance, long theNodeID, MovieController theMC)
  1353. {
  1354. #pragma unused(theNodeID)
  1355.  
  1356.     OSErr        myErr = noErr;
  1357.  
  1358.     if ((theInstance == NULL) || (theMC == NULL))
  1359.         return(paramErr);
  1360.         
  1361.     /////// 
  1362.     // all nodes
  1363.     /////// 
  1364.         
  1365.     // display the back button only if it's a multinode movie
  1366.     if (QTVRUtils_IsMultiNode(theInstance))
  1367.         QTVRUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressBackBtn);
  1368.     else
  1369.         QTVRUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressBackBtn);
  1370.  
  1371.     // display the show-hot-spot button only if there are hotspots in the node
  1372.     if (QTVRUtils_IsHotSpotInNode(theInstance))
  1373.         QTVRUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressHotSpotBtn);
  1374.     else
  1375.         QTVRUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressHotSpotBtn);
  1376.  
  1377.     /////// 
  1378.     // panoramic nodes
  1379.     /////// 
  1380.     
  1381.     if (QTVRUtils_IsPanoNode(theInstance)) {
  1382.     
  1383.         // hide the translate button
  1384.         QTVRUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1385.         
  1386.     } else {
  1387.     
  1388.     /////// 
  1389.     // object nodes
  1390.     /////// 
  1391.         
  1392.         // show the translate button, but only if translation is available
  1393.         if (QTVRUtils_IsTranslateAvailable(theInstance))
  1394.             QTVRUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1395.         else
  1396.             QTVRUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1397.     }
  1398.     
  1399.     return(myErr);
  1400. }
  1401.  
  1402.  
  1403. //////////
  1404. //
  1405. // QTVRUtils_StandardLeavingNodeProc
  1406. // A standard procedure for leaving a node.
  1407. // This function performs actions that many applications will want done when leaving a node:
  1408. //    * (this space for rent)
  1409. //
  1410. // We assume that when this procedure is called, the application has decided NOT to cancel the move;
  1411. // accordingly, we always return false in theCancel.
  1412. //
  1413. //////////
  1414.  
  1415. PASCAL_RTN OSErr QTVRUtils_StandardLeavingNodeProc (QTVRInstance theInstance, long fromNodeID, long toNodeID, Boolean *theCancel, MovieController theMC)
  1416. {
  1417. #pragma unused(fromNodeID, toNodeID)
  1418.  
  1419.     OSErr        myErr = noErr;
  1420.  
  1421.     if ((theInstance == NULL) || (theMC == NULL))
  1422.         return(paramErr);
  1423.     
  1424.     // nothing yet....
  1425.  
  1426.     *theCancel = false;
  1427.     return(myErr);
  1428. }
  1429.  
  1430.